package com.norteksoft.struts.dao;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.norteksoft.struts.dao.support.Page;


/**
 * 负责为单个Entity对象提供CRUD操作的Hibernate DAO基类.
 * <p/>
 * 子类只要在类定义时指定所管理Entity的Class, 即拥有对单个Entity对象的CRUD操作.
 * <pre>
 * public class UserManager extends HibernateEntityDao<User> {
 * }
 * </pre>
 *
 * @author calvin
 * @see HibernateGenericDao
 */

public class HibernateEntityDao extends HibernateDaoSupport implements EntityDao {

	protected String entityClass;// DAO所管理的Entity类型.

	
	protected Class getEntityClass() {
		Class clazz=null;
		try {
			clazz= Class.forName(entityClass);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return clazz;
	}
	
	
	public void setEntityClass(String entityClass) {
		this.entityClass = entityClass;
	}


	public Object get(Serializable id) {
		// TODO Auto-generated method stub
		return getHibernateTemplate().load(getEntityClass(), id);
	}

	public int getCount() {
		// TODO Auto-generated method stub
		List count=getHibernateTemplate().find("select count(*) from "+entityClass);
		return ((Long)count.get(0)).intValue();
	}
	
	private Query createQuery(String hql, Object[] parameters) {
		Query query = getSession().createQuery(hql);
		if(parameters==null)
			return query;
		for (int i = 0; i < parameters.length; i++) {
			query.setParameter(i, parameters[i]);
		}
		return query;
	}
	/**
	 * 分页查询函数，使用hql.
	 *
	 * @param pageNo 页号,从1开始.
	 */
	public Page pagedQuery(String hql, int pageNo, int pageSize, Object[] parameters) {
		// Count查询
		String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));
		List countlist = getHibernateTemplate().find(countQueryString, parameters);
		int totalCount = ((Long) countlist.get(0)).intValue();

		if (totalCount < 1)
			return new Page();
		// 实际查询返回分页对象
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		Query query = createQuery(hql, parameters);
		List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();

		return new Page(startIndex, totalCount, pageSize, list);
	}
	
	public List list(final String query, final int start, final int pageSize,final Object[] parameters) {
		
		List list=getHibernateTemplate().executeFind(new HibernateCallback(){
			
			public Object doInHibernate(Session s) throws HibernateException, SQLException {
				// TODO Auto-generated method stub
				Query q=s.createQuery(query);
				if(parameters!=null){
					for(int i=0;i<parameters.length;i++){
						q.setParameter(i, parameters[i]);
					}
				}
				//Projections.rowCount();
				q.setFirstResult(start);
				q.setMaxResults(pageSize);
				return q.list();
			}
		});
		return list;
	}

	public void save(Object obj) {
		// TODO Auto-generated method stub
		getHibernateTemplate().saveOrUpdate(obj);
	}

	public List listAll() {
		// TODO Auto-generated method stub
		return getHibernateTemplate().find("from "+entityClass);
	}
	
	public void remove(Object o) {
		// TODO Auto-generated method stub
		getHibernateTemplate().delete(o);
	}
	
	public void removeById(Serializable id) {
		getHibernateTemplate().delete(get(id));
	}
	
	/**
	 * 去除hql的select 子句，未考虑union的情况,用于pagedQuery.
	 *
	 * @see #pagedQuery(String,int,int,Object[])
	 */
	private static String removeSelect(String hql) {
		int beginPos = hql.toLowerCase().indexOf("from");
		return hql.substring(beginPos);
	}

	/**
	 * 去除hql的orderby 子句，用于pagedQuery.
	 *
	 * @see #pagedQuery(String,int,int,Object[])
	 */
	private static String removeOrders(String hql) {
		Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		StringBuffer sb = new StringBuffer();
		while (m.find()) {
			m.appendReplacement(sb, "");
		}
		m.appendTail(sb);
		return sb.toString();
	}
}
